package com.ssy.lingxi.order.serviceimpl.feign;

import com.ssy.lingxi.common.constant.manage.ShopTypeEnum;
import com.ssy.lingxi.common.constant.member.MemberLevelTypeEnum;
import com.ssy.lingxi.common.constant.product.PriceTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignRelationVO;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.response.MemberFeignRelationRightDetailVO;
import com.ssy.lingxi.order.model.bo.InventoryProductBO;
import com.ssy.lingxi.order.model.bo.OrderProductBO;
import com.ssy.lingxi.order.model.bo.VendorProductBO;
import com.ssy.lingxi.order.model.constant.OrderFreightTypeEnum;
import com.ssy.lingxi.order.model.constant.OrderProductDeliverTypeEnum;
import com.ssy.lingxi.order.model.constant.OrderPromotionTypeEnum;
import com.ssy.lingxi.order.model.dto.*;
import com.ssy.lingxi.order.service.feign.IMemberFeignService;
import com.ssy.lingxi.order.service.feign.IProductFeignService;
import com.ssy.lingxi.order.utils.NumberUtil;
import com.ssy.lingxi.order.utils.OrderStringUtil;
import com.ssy.lingxi.product.api.feign.FreightSpaceControllerFeign;
import com.ssy.lingxi.product.api.feign.ICommodityFeign;
import com.ssy.lingxi.product.api.model.request.CommoditySold;
import com.ssy.lingxi.product.api.model.request.SimpleIdListRequest;
import com.ssy.lingxi.product.api.model.request.feign.CommodityPriceRequest;
import com.ssy.lingxi.product.api.model.request.warehouse.DeductInventoryRequest;
import com.ssy.lingxi.product.api.model.request.warehouse.InventoryByProductIdRequest;
import com.ssy.lingxi.product.api.model.response.commodity.CommodityOrderResponse;
import com.ssy.lingxi.product.api.model.response.commodity.GoodsIdAndFirstCategoryIdResponse;
import com.ssy.lingxi.product.api.model.response.commodity.UpperCommodityResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  商品服务Feign接口调用类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-30
 */
@Service
public class ProductFeignServiceImpl implements IProductFeignService {
    private static final Logger logger = LoggerFactory.getLogger(ProductFeignServiceImpl.class);

    @Resource
    private FreightSpaceControllerFeign freightSpaceControllerFeign;

    @Resource
    private ICommodityFeign commodityFeign;

    @Resource
    private IMemberFeignService memberFeignService;

    /**
     * 批量校验商品价格
     *
     * @param buyerMemberId  采购会员Id
     * @param buyerRoleId    采购会员角色Id
     * @param shopId          商城Id
     * @param memberType      会员类型，用于判断是会员商品，还是渠道商品
     * @param skuIds          商品SkuId列表
     * @return 校验结果
     */
    @Override
    public Wrapper<Map<Long, Map<String, Double>>> batchCheckProductPrice(Long buyerMemberId, Long buyerRoleId, Long shopId, Integer memberType, List<Long> skuIds) {
        try {
            CommodityPriceRequest request = new CommodityPriceRequest();
            request.setMemberId(buyerMemberId);
            request.setMemberRoleId(buyerRoleId);
            request.setShopId(shopId);
            request.setCommodityType(MemberLevelTypeEnum.getCodeByMemberType(memberType).equals(MemberLevelTypeEnum.MERCHANT.getCode()) ? 1 : 2);
            request.setCommoditySkuIdList(skuIds);
            return Wrapper.success(commodityFeign.getCommodityPriceBatch(request));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_PRODUCT_ERROR);
        }
    }

    /**
     * 扣减供应商库存
     *
     * @param buyerMemberId  采购会员Id
     * @param buyerRoleId    采购会员角色Id
     * @param orderId        订单Id
     * @param shopId         商城Id
     * @param shopType       商城类型（用于判断是渠道商城还是会员商城）
     * @param products       商品和采购数量
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> deductInventory(Long buyerMemberId, Long buyerRoleId, Long orderId, Long shopId, Integer shopType, List<InventoryProductBO> products) {
        InventoryByProductIdRequest request = new InventoryByProductIdRequest();
        request.setSupplyMembersId(buyerMemberId);
        request.setMemberRoleId(buyerRoleId);
        request.setOrderId(orderId);
        request.setShopId(shopId);
        request.setDeductInventoryRequests(products.stream().map(product -> {
            DeductInventoryRequest r = new DeductInventoryRequest();
            if(shopType.equals(ShopTypeEnum.ENTERPRISE.getCode()) || shopType.equals(ShopTypeEnum.SCORE.getCode()) || shopType.equals(ShopTypeEnum.PURCHASE.getCode())) {
                r.setProductId(product.getProductId());
                r.setProductSkuId(product.getSkuId());
                r.setProductName(product.getProductName());
            } else {
                r.setChannelProductId(product.getProductId());
                r.setChannelProductSkuId(product.getSkuId());
                r.setProductSkuId(product.getStockId());
                r.setChannelProductName(product.getProductName());
            }
            r.setPurchaseCount(product.getQuantity().doubleValue());
            return r;
        }).collect(Collectors.toList()));
        return freightSpaceControllerFeign.deductInventory(request);
    }

    /**
     * 返还供应商库存
     *
     * @param buyerMemberId  采购会员Id
     * @param buyerRoleId    采购会员角色Id
     * @param orderId        订单Id
     * @param shopId         商城Id
     * @param shopType       商城类型（用于判断是渠道商城还是会员商城）
     * @param products       商品和返还数量
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> resumeInventory(Long buyerMemberId, Long buyerRoleId, Long orderId, Long shopId, Integer shopType, List<InventoryProductBO> products) {
        InventoryByProductIdRequest request = new InventoryByProductIdRequest();
        request.setSupplyMembersId(buyerMemberId);
        request.setMemberRoleId(buyerRoleId);
        request.setOrderId(orderId);
        request.setShopId(shopId);
        request.setDeductInventoryRequests(products.stream().map(product -> {
            DeductInventoryRequest r = new DeductInventoryRequest();
            if(shopType.equals(ShopTypeEnum.ENTERPRISE.getCode()) || shopType.equals(ShopTypeEnum.SCORE.getCode())) {
                r.setProductId(product.getProductId());
                r.setProductSkuId(product.getSkuId());
                r.setProductName(product.getProductName());
            } else {
                r.setChannelProductId(product.getProductId());
                r.setChannelProductSkuId(product.getSkuId());
                r.setProductSkuId(product.getStockId());
                r.setChannelProductName(product.getProductName());
            }
            r.setPurchaseCount(product.getQuantity().doubleValue());
            return r;
        }).collect(Collectors.toList()));
        return freightSpaceControllerFeign.deductReturn(request);
    }

    /**
     * 根据订单中的上游供应商与供应商商品，查询上游供应商商品信息
     *
     * @param roleId         当前订单供应商要转单的服务消费者角色Id
     * @param vendorProducts 供应商会“会员商品”SkuId列表
     * @return 上游供应商商品列表
     */
    @Override
    public Wrapper<List<SupplyProductDTO>> findSupplyProducts(Long roleId, List<VendorProductBO> vendorProducts) {
        List<Long> skuIds = vendorProducts.stream().flatMap(vendorProduct -> vendorProduct.getProducts().stream().map(OrderProductBO::getSkuId)).distinct().collect(Collectors.toList());
        Wrapper<List<UpperCommodityResponse>> commodityResult = commodityFeign.getUpperCommodityByCommoditySkuIdList(skuIds);
        if(commodityResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(commodityResult.getCode(), commodityResult.getMessage());
        }

        //如果返回结果中包含了“允许使用会员折扣购买”，查询会员折扣
        List<MemberFeignRelationVO> vendorRelations = commodityResult.getData().stream().filter(r -> Objects.nonNull(r.getIsMemberPrice()) && r.getIsMemberPrice()).map(response -> {
            VendorProductBO vendorProduct = vendorProducts.stream().filter(vendorProductBO -> vendorProductBO.getProducts().stream().anyMatch(product -> product.getSkuId().equals(response.getSubCommoditySkuId()))).findFirst().orElse(null);
            if(vendorProduct == null) {
                return null;
            } else {
                MemberFeignRelationVO relationVO = new MemberFeignRelationVO();
                relationVO.setSubMemberId(vendorProduct.getVendorMemberId());
                relationVO.setSubRoleId(roleId);
                relationVO.setUpperMemberId(response.getMemberId());
                relationVO.setUpperRoleId(response.getMemberRoleId());
                return relationVO;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());

        //从会员服务查询会员折扣
        Wrapper<List<MemberFeignRelationRightDetailVO>> memberResult = memberFeignService.batchFindMemberPriceRight(vendorRelations);
        if(memberResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(memberResult.getCode(), memberResult.getMessage());
        }

        return Wrapper.success(commodityResult.getData().stream().map(commodity -> {
            SupplyProductDTO product = new SupplyProductDTO();
            product.setVendorSkuId(commodity.getSubCommoditySkuId());
            product.setSupplyMemberId(commodity.getMemberId());
            product.setSupplyRoleId(commodity.getMemberRoleId());
            product.setSupplyMemberName(commodity.getMemberName());
            product.setProductId(commodity.getCommodityId());
            product.setProductNo(StringUtils.hasLength(commodity.getCode()) ? commodity.getCode() : "");
            product.setSkuId(commodity.getId());
            product.setName(StringUtils.hasLength(commodity.getName()) ? commodity.getName() : "");
            product.setCategory(StringUtils.hasLength(commodity.getCustomerCategoryName()) ? commodity.getCustomerCategoryName() : "");
            product.setBrand(StringUtils.hasLength(commodity.getBrandName()) ? commodity.getBrandName() : "");
            product.setUnit(StringUtils.hasLength(commodity.getUnitName()) ? commodity.getUnitName() : "");
            product.setSpec(StringUtils.hasLength(commodity.getAttribute()) ? commodity.getAttribute() : "");
            product.setLogo(StringUtils.hasLength(commodity.getMainPic()) ? commodity.getMainPic() : "");
            product.setPriceType(NumberUtil.isNullOrZero(commodity.getPriceType()) ? PriceTypeEnum.Cash.getCode() : commodity.getPriceType());
            product.setPrices(CollectionUtils.isEmpty(commodity.getUnitPrice()) ? new HashMap<>() : commodity.getUnitPrice());
            product.setDiscount(Objects.isNull(commodity.getIsMemberPrice()) ? BigDecimal.ONE : (commodity.getIsMemberPrice() ? memberResult.getData().stream().filter(right -> right.getUpperMemberId().equals(commodity.getMemberId()) && right.getUpperRoleId().equals(commodity.getMemberRoleId())).map(MemberFeignRelationRightDetailVO::getParameter).findFirst().orElse(BigDecimal.ONE) : BigDecimal.ONE));
            product.setStock(NumberUtil.isNullOrZero(commodity.getStockCount()) ? BigDecimal.ZERO : BigDecimal.valueOf(commodity.getStockCount()));
            product.setTaxRate(NumberUtil.isNullOrZero(commodity.getTaxRate()) ? BigDecimal.ZERO : BigDecimal.valueOf(commodity.getTaxRate()).divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
            product.setTax(!Objects.isNull(product.getTaxRate()) && product.getTaxRate().compareTo(BigDecimal.ZERO) > 0);
            product.setDeliverType(commodity.getLogistics() == null ? OrderProductDeliverTypeEnum.NO_DELIVERY.getCode() : (NumberUtil.isNullOrZero(commodity.getLogistics().getDeliveryType()) ? OrderProductDeliverTypeEnum.NO_DELIVERY.getCode() : commodity.getLogistics().getDeliveryType()));
            product.setFreightType(commodity.getLogistics() == null ? OrderFreightTypeEnum.NONE.getCode() : (NumberUtil.isNullOrZero(commodity.getLogistics().getCarriageType()) ? OrderFreightTypeEnum.NONE.getCode() : commodity.getLogistics().getCarriageType()));
            product.setWeight(commodity.getLogistics() == null ? BigDecimal.ZERO : (NumberUtil.isNullOrZero(commodity.getLogistics().getWeight()) ? BigDecimal.ZERO : BigDecimal.valueOf(commodity.getLogistics().getWeight())));
            product.setLogisticsTemplateId(commodity.getLogistics() == null ? 0L : (NumberUtil.notNullAndPositive(commodity.getLogistics().getTemplateId()) ? commodity.getLogistics().getTemplateId() : 0L));
            product.setAddressId(commodity.getLogistics() == null ? 0L : (NumberUtil.notNullAndPositive(commodity.getLogistics().getSendAddress()) ? commodity.getLogistics().getSendAddress() : 0L));
            product.setReceiver("");
            product.setPhone("");
            product.setAddress("");
            return product;
        }).collect(Collectors.toList()));
    }

    /**
     * 更新商品售卖数量
     *
     * @param shopId        商城Id
     * @param shopType      商城类型枚举
     * @param buyerMemberId 采购会员Id
     * @param buyerRoleId   采购会员角色Id
     * @param buyerMemberName 采购会员名称
     * @param skuQuantities 商品SkuId+采购数量
     */
    @Async
    @Override
    public void updateProductSoldCountAsync(Long shopId, Integer shopType, Long buyerMemberId, Long buyerRoleId, String buyerMemberName, List<OrderProductStockDTO> skuQuantities) {
        CommoditySold sold = new CommoditySold();
        sold.setShopId(shopId);
        sold.setMemberId(buyerMemberId);
        sold.setMemberRoleId(buyerRoleId);
        sold.setMemberName(buyerMemberName);
        try {
            switch (ShopTypeEnum.parseCode(shopType)) {
                case ENTERPRISE:
                case SCORE:
                    sold.setCommodityCountMap(new HashMap<>(skuQuantities.stream().collect(Collectors.toMap(OrderProductStockDTO::getSkuId, s -> s.getQuantity().doubleValue()))));
                    commodityFeign.updateCommoditySold(sold);
                    break;
                case CHANNEL:
                case CHANNEL_SELF:
                case CHANNEL_SCORE:
                    sold.setCommodityCountMap(new HashMap<>(skuQuantities.stream().collect(Collectors.toMap(OrderProductStockDTO::getSkuId, s -> s.getQuantity().doubleValue()))));
                    commodityFeign.updateChannelCommoditySold(sold);
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            logger.error("通知商品服务更新商品售卖数量错误：" + e.getMessage() + "\n 参数:" + OrderStringUtil.serializeObject(sold));
        }
    }

    /**
     * 查询商品详细信息
     *
     * @param shopId               商城Id
     * @param buyerMemberId        采购会员Id
     * @param buyerRoleId          采购会员角色Id
     * @param buyerMemberLevelType 采购会员等级类型
     * @param products               商品SkuId列表
     * @return 转换后的商品信息列表
     */
    @Override
    public Wrapper<List<OrderProductDetailDTO>> findProductDetails(Long shopId, Long buyerMemberId, Long buyerRoleId, Integer buyerMemberLevelType, List<ProductSkuDTO> products) {
        CommodityPriceRequest request = new CommodityPriceRequest();
        request.setMemberId(buyerMemberId);
        request.setMemberRoleId(buyerRoleId);
        request.setCommodityType(buyerMemberLevelType.equals(MemberLevelTypeEnum.MERCHANT.getCode()) ? 1 : 2);
        request.setShopId(shopId);
        request.setCommoditySkuIdList(products.stream().map(ProductSkuDTO::getSkuId).collect(Collectors.toList()));
        try {
            List<CommodityOrderResponse> resultList = commodityFeign.getCommodityListByOrder(request);
            if(CollectionUtils.isEmpty(resultList) || products.stream().anyMatch(s -> resultList.stream().noneMatch(product -> product.getId().equals(s.getSkuId())))) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
            }

            List<OrderProductDetailDTO> productDetails = products.stream().map(product -> {
                OrderProductDetailDTO productDetail = new OrderProductDetailDTO();
                productDetail.setSkuId(product.getSkuId());
                productDetail.setBuyerMemberId(product.getBuyerMemberId());
                productDetail.setBuyerRoleId(product.getBuyerRoleId());
                productDetail.setVendorMemberId(product.getVendorMemberId());
                productDetail.setVendorRoleId(product.getVendorRoleId());
                productDetail.setPromotionType(product.getPromotionType());
                productDetail.setGroupNo(product.getGroupNo());
                productDetail.setParentSkuId(product.getParentSkuId());
                productDetail.setQuantity(product.getQuantity());

                resultList.stream().filter(r -> r.getId().equals(product.getSkuId())).findFirst().ifPresent(result -> {
                    productDetail.setProductId(result.getCommodityId());
                    productDetail.setSkuId(result.getId());
                    productDetail.setPublished(result.getIsPublish() == null ? false : result.getIsPublish());
                    productDetail.setName(result.getName());
                    productDetail.setLogo(result.getMainPic());
                    productDetail.setCategory(result.getCustomerCategoryName());
                    productDetail.setBrand(result.getBrandName());
                    productDetail.setUnit(result.getUnitName());
                    productDetail.setSpec(StringUtils.hasLength(result.getAttribute()) ? result.getAttribute() : "");
                    productDetail.setMinOrder(NumberUtil.isNullOrNegative(result.getMinOrder()) ? BigDecimal.ZERO : BigDecimal.valueOf(result.getMinOrder()));
                    productDetail.setDiscountable(result.getIsMemberPrice() == null ? false : result.getIsMemberPrice());
                    productDetail.setPriceMap(result.getUnitPrice());
                    productDetail.setPriceType(result.getPriceType());
                    productDetail.setTax(!NumberUtil.isNullOrNegative(result.getTaxRate()));
                    productDetail.setTaxRate(NumberUtil.isNullOrNegative(result.getTaxRate()) ? BigDecimal.ZERO : BigDecimal.valueOf(result.getTaxRate()).divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));

                    //物流信息
                    productDetail.setDeliveryType(result.getLogistics() == null || NumberUtil.isNullOrNegativeZero(result.getLogistics().getDeliveryType()) ? OrderProductDeliverTypeEnum.LOGISTICS.getCode() : result.getLogistics().getDeliveryType());
                    productDetail.setFreightType(result.getLogistics() == null || NumberUtil.isNullOrNegativeZero(result.getLogistics().getCarriageType()) ? OrderFreightTypeEnum.VENDOR.getCode() : result.getLogistics().getCarriageType());
                    productDetail.setWeight(result.getLogistics() == null || NumberUtil.isNullOrNegativeZero(result.getLogistics().getWeight()) ? BigDecimal.ZERO : BigDecimal.valueOf(result.getLogistics().getWeight()));
                    productDetail.setLogisticsTemplateId(result.getLogistics() == null || result.getLogistics().getUseTemplate() == null || result.getLogistics().getUseTemplate().equals(false) || NumberUtil.isNullOrNegativeZero(result.getLogistics().getTemplateId()) ? 0L : result.getLogistics().getTemplateId());
                    productDetail.setConsigneeId(result.getLogistics() == null || NumberUtil.isNullOrNegativeZero(result.getLogistics().getSendAddress()) ? 0L : result.getLogistics().getSendAddress());
                    productDetail.setCrossBorder(result.getIsCrossBorder());

                    //要查询会员服务设置
                    productDetail.setDiscount(!productDetail.getDiscountable() ? BigDecimal.ONE : BigDecimal.ZERO);
                });

                return productDetail;
            }).collect(Collectors.toList());

            //从会员服务查询折扣
            List<MemberFeignRelationVO> vendorRelations  = productDetails.stream().filter(OrderProductDetailDTO::getDiscountable).map(r -> {
                MemberFeignRelationVO relationVO = new MemberFeignRelationVO();
                relationVO.setSubMemberId(r.getBuyerMemberId());
                relationVO.setSubRoleId(r.getBuyerRoleId());
                relationVO.setUpperMemberId(r.getVendorMemberId());
                relationVO.setUpperRoleId(r.getVendorRoleId());
                return relationVO;
            }).collect(Collectors.toList());

            Wrapper<List<MemberFeignRelationRightDetailVO>> rightResult = memberFeignService.batchFindMemberPriceRight(vendorRelations);
            if(rightResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(rightResult.getCode(), rightResult.getMessage());
            }

            return Wrapper.success(productDetails.stream().peek(r -> {
                //被换购的商品没有会员折扣
                if(r.getPromotionType().equals(OrderPromotionTypeEnum.EXCHANGED.getCode())) {
                    r.setDiscountable(false);
                    r.setDiscount(BigDecimal.ONE);
                } else if(r.getDiscountable()) {
                    rightResult.getData().stream().filter(right -> right.getSubMemberId().equals(r.getBuyerMemberId()) && right.getSubRoleId().equals(r.getBuyerRoleId()) && right.getUpperMemberId().equals(r.getVendorMemberId()) && right.getUpperRoleId().equals(r.getVendorRoleId())).findFirst().ifPresent(right -> r.setDiscount(right.getParameter()));
                }
            }).collect(Collectors.toList()));
        } catch (BusinessException e) {
            return Wrapper.fail(e.getCode(), e.getMessage());
        }
    }

    /**
     * 查询Srm订单物料一级品类
     *
     * @param productIds 物料商品Id列表
     * @return 查询结果
     */
    @Override
    public List<OrderProductCategoryDTO> findProductCategories(List<Long> productIds) {
        if(CollectionUtils.isEmpty(productIds)) {
            return new ArrayList<>();
        }

        try {
            SimpleIdListRequest request = new SimpleIdListRequest();
            request.setIdList(productIds);
            logger.info("从商品服务查询物料一级品类Id => " + OrderStringUtil.serializeObject(request));

            Wrapper<List<GoodsIdAndFirstCategoryIdResponse>> result = commodityFeign.getGoodsFirstCategoryIdList(request);
            logger.info("从商品服务查询物料一级品类返回 => " + OrderStringUtil.serializeObject(result));

            if(result.getCode() == ResponseCode.SUCCESS.getCode()) {
                return CollectionUtils.isEmpty(result.getData()) ? new ArrayList<>() : result.getData().stream().map(r -> new OrderProductCategoryDTO(r.getGoodsId(), r.getCategoryId())).collect(Collectors.toList());
            }

            logger.error("从商品服务查询物料一级品类Id错误, code:" + result.getCode() + ", msg:" + result.getMessage());
            return new ArrayList<>();
        } catch (Exception e) {
            logger.error("从商品服务查询物料一级品类Id异常, msg:" + e.getMessage());
            return new ArrayList<>();
        }
    }
}
